﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace HY.Common
{
    public static class HttpHelper
    {
        private static readonly string ApiUrl = INIHelper.Read("ALL", "ApiUrl");
        private static int Timeout = 5000;
        static HttpHelper()
        {
            if (ApiUrl.StartsWith("https"))
                SetCertificatePolicy();
        }

        public static int UserId = 0;

        public static string UserName = string.Empty;

        private static void AddHeader(this HttpWebRequest request)
        {
            request.Headers.Add("UserId", UserId.ToString());
            request.Headers.Add("UserName", UserName);
        }

        #region Get请求        
        /// <summary>
        /// 发送GET请求
        /// </summary>
        /// <param name="path">请求URL，如果需要传参，在URL末尾加上“？+参数名=参数值”即可</param>
        /// <returns></returns>
        public static string Get(string path, Dictionary<string, string> headers = null)
        {
            HttpWebResponse response = GetResponse(path, headers);
            using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
            {
                return sr.ReadToEnd();
            }
        }

        /// <summary>
        /// 发送GET请求
        /// </summary>
        /// <param name="path">请求URL，如果需要传参，在URL末尾加上“？+参数名=参数值”即可</param>
        /// <returns></returns>
        public static byte[] GetFile(string path, Dictionary<string, string> headers = null)
        {
            HttpWebResponse response = GetResponse(path, headers);
            Stream stream = response.GetResponseStream();
            byte[] bytes = new Byte[response.ContentLength];
            int readecount = 0;
            while (readecount < (int)response.ContentLength)
            {
                readecount += stream.Read(bytes, readecount, (int)response.ContentLength - readecount);
            }
            return bytes;
        }
        private static HttpWebResponse GetResponse(string path, Dictionary<string, string> headers = null)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(ApiUrl + path);
            if (headers != null)
            {
                foreach (var header in headers)
                    request.Headers.Add(header.Key, header.Value);
            }
            request.Method = "GET";
            request.Timeout = Timeout;
            request.AddHeader();
            return (HttpWebResponse)request.GetResponse();
        }
        #endregion

        #region Post请求
        ///<summary>
        ///采用https协议访问网络(Post方式)
        ///</summary>
        ///<param name="path">接口路径</param>
        ///<param name="paras">发送的数据</param>
        ///<returns></returns>
        public static string Post(string path, Dictionary<string, string> paras, Dictionary<string, string> headers = null)
        {
            string contentType = "application/x-www-form-urlencoded";
            return HttpRequest(path, ParasToString(paras), "post", contentType, headers);
        }
        ///<summary>
        ///采用https协议访问网络(Post方式，参数传送方式：Raw)
        ///</summary>
        ///<param name="path">接口路径</param>
        ///<param name="jsonstring"></param>
        ///<returns></returns>
        public static string Post(string path, string jsonstring, Dictionary<string, string> headers = null)
        {
            string contentType = "application/json";
            return HttpRequest(path, jsonstring, "post", contentType, headers);
        }
        /// <summary>
        /// 上传单文件（多文件在此基础上修改）
        /// </summary>
        /// <param name="path">接口地址</param>
        /// <param name="paras">其他参数</param>
        /// <param name="paramName">文件参数名</param>
        /// <param name="fileName">文件名</param>
        /// <param name="file">文件字节数组</param>
        /// <returns></returns>
        public static string Post(string path, Dictionary<string, string> paras, string paramName, string fileName, byte[] file, Dictionary<string, string> headers = null)
        {
            return UploadFile(path, paras, paramName, fileName, file, "POST", headers);
        }
        #endregion

        #region Put请求
        ///<summary>
        ///采用https协议访问网络(Post方式)
        ///</summary>
        ///<param name="path">接口路径</param>
        ///<param name="paras">发送的数据</param>
        ///<returns></returns>
        public static string Put(string path, Dictionary<string, string> paras, Dictionary<string, string> headers = null)
        {
            string contentType = "application/x-www-form-urlencoded";
            return HttpRequest(path, ParasToString(paras), "put", contentType, headers);
        }
        ///<summary>
        ///采用https协议访问网络(Post方式，参数传送方式：Raw)
        ///</summary>
        ///<param name="path">接口路径</param>
        ///<param name="jsonstring"></param>
        ///<returns></returns>
        public static string Put(string path, string jsonstring, Dictionary<string, string> headers = null)
        {
            string contentType = "application/json";
            return HttpRequest(path, jsonstring, "put", contentType, headers);
        }
        /// <summary>
        /// 上传单文件（多文件在此基础上修改）
        /// </summary>
        /// <param name="path">接口地址</param>
        /// <param name="paras">其他参数</param>
        /// <param name="paramName">文件参数名</param>
        /// <param name="fileName">文件名</param>
        /// <param name="file">文件字节数组</param>
        /// <returns></returns>
        public static string Put(string path, Dictionary<string, string> paras, string paramName, string fileName, byte[] file, Dictionary<string, string> headers = null)
        {
            return UploadFile(path, paras, paramName, fileName, file, "PUT", headers);
        }
        #endregion

        #region 上传文件
        /// <summary>
        /// 上传单文件（多文件在此基础上修改）
        /// </summary>
        /// <param name="path">接口地址</param>
        /// <param name="paras">其他参数</param>
        /// <param name="paramName">文件参数名</param>
        /// <param name="fileName">文件名</param>
        /// <param name="file">文件字节数组</param>
        /// <returns></returns>
        public static string UploadFile(string path, Dictionary<string, string> paras, string paramName, string fileName, byte[] file, string method, Dictionary<string, string> headers = null)
        {
            string boundary = DateTime.Now.Ticks.ToString("x");//分隔符
            byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");//分隔符流

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(ApiUrl + path);
            request.ContentType = "multipart/form-data; boundary=" + boundary;
            request.Method = method;
            request.KeepAlive = true;
            request.AddHeader();
            if (headers != null)
            {
                foreach (var item in headers)
                {
                    request.Headers.Add(item.Key, item.Value);
                }
            }
            //request.Credentials = CredentialCache.DefaultCredentials;
            Stream requestStream = request.GetRequestStream();

            //添加参数
            foreach (var para in paras)
            {
                requestStream.Write(boundarybytes, 0, boundarybytes.Length);
                string formitem = string.Format("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}", para.Key, para.Value);
                byte[] formitembytes = Encoding.UTF8.GetBytes(formitem);
                requestStream.Write(formitembytes, 0, formitembytes.Length);
            }
            requestStream.Write(boundarybytes, 0, boundarybytes.Length);

            //添加文件参数
            string header = string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", paramName, fileName);
            byte[] headerbytes = Encoding.UTF8.GetBytes(header);
            requestStream.Write(headerbytes, 0, headerbytes.Length);
            //添加文件流
            requestStream.Write(file, 0, file.Length);


            byte[] footer = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
            requestStream.Write(footer, 0, footer.Length);
            requestStream.Close();

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
            {
                return sr.ReadToEnd();
            }
        }
        /// <summary>
        /// 上传单文件（多文件在此基础上修改）
        /// </summary>
        /// <param name="path">接口地址</param>
        /// <param name="paras">其他参数</param>
        /// <param name="paramName">文件参数名</param>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static string UploadFile(string path, Dictionary<string, string> paras, string paramName, string filePath, string method, Dictionary<string, string> headers = null)
        {
            string boundary = DateTime.Now.Ticks.ToString("x");
            byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");//分隔符流

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(ApiUrl + path);
            request.ContentType = "multipart/form-data; boundary=" + boundary;
            request.Method = method;
            request.KeepAlive = true;
            request.AddHeader();
            if (headers != null)
            {
                foreach (var item in headers)
                {
                    request.Headers.Add(item.Key, item.Value);
                }
            }
            //request.Credentials = CredentialCache.DefaultCredentials;
            Stream requestStream = request.GetRequestStream();

            //添加参数
            foreach (var para in paras)
            {
                requestStream.Write(boundarybytes, 0, boundarybytes.Length);
                string formitem = string.Format("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}", para.Key, para.Value);
                byte[] formitembytes = Encoding.UTF8.GetBytes(formitem);
                requestStream.Write(formitembytes, 0, formitembytes.Length);
            }
            requestStream.Write(boundarybytes, 0, boundarybytes.Length);

            //添加文件
            string header = string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", paramName, filePath);
            byte[] headerbytes = Encoding.UTF8.GetBytes(header);
            requestStream.Write(headerbytes, 0, headerbytes.Length);
            FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            byte[] buffer = new byte[4096];
            int bytesRead = 0;
            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
            {
                requestStream.Write(buffer, 0, bytesRead);
            }
            fileStream.Close();

            byte[] footer = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
            requestStream.Write(footer, 0, footer.Length);
            requestStream.Close();

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
            {
                return sr.ReadToEnd();
            }
        }
        #endregion

        ///<summary>
        ///采用https协议访问网络
        ///</summary>
        ///<param name="path">接口路径</param>
        ///<param name="paras">发送的参数</param>
        ///<param name="encoding">编码格式</param>
        ///<param name="contentType">request.ContentType</param>
        ///<param name="headers">request.headers</param>
        ///<returns></returns>
        private static string HttpRequest(string path, string paras, string method, string contentType, Dictionary<string, string> headers = null)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(ApiUrl + path);
            request.Method = method;
            request.Accept = "text/html, application/xhtml+xml, */*";
            request.ContentType = contentType;
            request.Timeout = Timeout;
            request.AddHeader();
            if (headers != null)
            {
                foreach (var header in headers)
                {
                    request.Headers.Add(header.Key, header.Value);
                }
            }
            byte[] buffer = Encoding.UTF8.GetBytes(paras);
            request.ContentLength = buffer.Length;
            request.GetRequestStream().Write(buffer, 0, buffer.Length);

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
            {
                return sr.ReadToEnd();
            }
        }

        private static string ParasToString(Dictionary<string, string> paras)
        {
            StringBuilder parasstring = new StringBuilder();
            foreach (var para in paras)
            {
                parasstring.Append(string.Format("&{0}={1}", para.Key, para.Value));
            }
            if (parasstring.Length > 0)
                parasstring.Remove(0, 1);
            return parasstring.ToString();
        }

        #region Https连接设置安全认证
        /// <summary>
        /// 在发出请求前，解决未能建立安全通信通道问题，为这次连接设置安全认证，在程序启动时调用一次就行
        /// </summary>
        public static void SetCertificatePolicy()
        {
            ServicePointManager.ServerCertificateValidationCallback += RemoteCertificateValidate;
        }
        private static bool RemoteCertificateValidate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
        {
            return true;
        }
        #endregion

        #region 检测用户计算机是否已连接网络
        [DllImport("wininet.dll")]
        private extern static bool InternetGetConnectedState(out int connectionDescription, int reservedValue);
        /// <summary>
        /// 检测用户计算机是否已连接网络
        /// </summary>
        /// <returns></returns>
        public static bool IsInternetState()
        {
            return InternetGetConnectedState(out _, 0);
        }
        #endregion
    }
}
